import decimal
import json
from collections import namedtuple

class DecimalEncoder(json.JSONEncoder):
    """
      json Decimal编码处理
    """
 
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return float(o)
        return super(DecimalEncoder, self).default(o)
    
#解决自定义对象序列化时报对象不支持序列化问题
def convert_to_builtin_type(obj):
    is_list = obj.__class__ == [].__class__
    is_set = obj.__class__ == set().__class__
    if is_list or is_set:
        obj_arr = []
        for o in obj:
            #把Object对象转换成Dict对象
            dict = {}
            dict.update(o.__dict__)
            obj_arr.append(dict)
        return obj_arr
    else:
        # for attr,value in obj.__dict__.items():
            #  if isinstance(attr, decimal.Decimal):
            #     attr = (float(attr))
        dict = {}
        dict.update(obj.__dict__)
        return dict

class JsonUtil:
    #将对象序列化为json字符串
    def ToJson(self,obj,cls = None):
        if cls == None:
            return json.dumps(obj,ensure_ascii = False,default = convert_to_builtin_type)
        else:
            return json.dumps(obj,cls= cls,ensure_ascii = False,default = convert_to_builtin_type)
        
    #将json字符串反序列化为对象
    #obj_hook：反序列化后的对象的类型，比如User，Order，OrderLog。这样就可以User.UserName,User.Age。否则只能User["UserName"],User["Age"]
    #注：需要反序列化后能获取User.UserName,User.Age类似数据，需要在User类的__init__方法定义为,d为字典，默认为空字典，方便实例化对象时传空参数，比如user = User()
    #    def __init__(self,d = {}):
    #    self.__dict__=d
    #附注：该定义构造函数的类实例化需参考如下操作：p1 = User({'Id':10,'UserName':'yhb','Age':100,'BD':'2017-7-15'})
    # user_obj = FromJson(user_json_str,User), type(user_obj) == type(User())
    def FromJson(self,jsonStr,obj_hook = None):
        if not obj_hook:
            # return json.loads(jsonStr,encoding='unicode')
            return json.loads(jsonStr)
        else:
            return json.loads(jsonStr,object_hook=obj_hook)

    # 将json字符串，转换为对象，FromJson方法如果没有指定obj_hook为具体类时，是返回字典的。objName可以指定对应的类，比如User
    def FromJsonToObject(self, JsonStr, objName = 'X'):
            return json.loads(JsonStr, object_hook=lambda d: namedtuple(objName, d.keys())(*d.values()))

    # 规范函数命名，小写下划线
    def from_json_to_real_object(self,json_str,class_name):
        dict_obj = json.loads(json_str)
        return class_name(**dict_obj)
        